package com.lazy.lib.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;


public class BigEndian {
	
	private static Logger logger = LoggerFactory.getLogger(BigEndian.class);

	/**
	 * 转成4个字节
	 * @param array
	 * @param index
	 * @param value
	 */
	public static void setLong4(byte[] array, int index, long value) {
        array[index]     = (byte) (value >>> 24);
        array[index + 1] = (byte) (value >>> 16);
        array[index + 2] = (byte) (value >>> 8);
        array[index + 3] = (byte) value;
	}
	
	/**
     * 将value总低48位数据转成6个字节
     * @param array
     * @param index
     * @param value
     */
    public static void setLong6(byte[] array, int index, long  value) {
        array[index] = (byte) (value >>> 40);
        array[index + 1] = (byte) (value >>> 32);
        array[index + 2] = (byte) (value >>> 24);
        array[index + 3] = (byte) (value >>> 16);
        array[index + 4] = (byte) (value >>> 8);
        array[index + 5] = (byte) value;
    }
    
    public static void setLong(byte[] array, int index, long  value) {
        array[index]     = (byte) (value >>> 56);
        array[index + 1] = (byte) (value >>> 48);
        array[index + 2] = (byte) (value >>> 40);
        array[index + 3] = (byte) (value >>> 32);
        array[index + 4] = (byte) (value >>> 24);
        array[index + 5] = (byte) (value >>> 16);
        array[index + 6] = (byte) (value >>> 8);
        array[index + 7] = (byte) value;
    }


	/**
	 * 转成2个字节
	 * @param array
	 * @param index
	 * @param value
	 */
    public static void setInt2(byte[] array, int index, int value) {
        array[index]     = (byte) (value >>> 8);
        array[index + 1] = (byte) value;
    }

    public static void setInt(byte[] array, int index, int value) {
        array[index]     = (byte) (value >>> 24);
        array[index + 1] = (byte) (value >>> 16);
        array[index + 2] = (byte) (value >>> 8);
        array[index + 3] = (byte) value;
    }
	
    public static void setShort(byte[] array, int index, int value) {
        array[index]     = (byte) (value >>> 8);
        array[index + 1] = (byte) value;
    }
    
    /**
     * 转成 Octet String
     * @param array
     * @param index
     * @param s
     * @param needLen 转成多少个字节， 不足补0
     */
    public static void setString(byte[] array, int index, String s, int needLen) {
        int len = s.length();
        for (int i = 0; i < needLen; i++) {
        	if (i < len) {
        		array[index + i] = ((byte) s.charAt(i));
        	} else {
        		array[index + i] = 0;
        	}
        }
    }
    
    public static void setOctetString(byte[] array, int index, String s, int needLen) {
		try {
			byte[] bOctetArray = s.getBytes("GBK");
	        int len = bOctetArray.length;
	        for (int i = 0; i < needLen; i++) {
	        	if (i < len) {
	        		array[index + i] = bOctetArray[i];
	        	} else {
	        		array[index + i] = 0;
	        	}
	        }
		} catch (UnsupportedEncodingException e) {
			logger.error("GBK is not supported! the reason is " + e.getMessage());
			//e.printStackTrace();
			logger.info("try to convert byte with charAt at string:" + s);
			setString(array, index, s, needLen);
		}
    }
    
    /** 返回字符串或者空字符串 */
    public static String getOctetString(byte[] array, int offset, int length) {
    	try {
			return new String(array, offset, length, "GBK");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
    	return "";
    }

    public static long getLong(byte[] array, int index) {
        return  ((long) array[index]     & 0xff) << 56 |
                ((long) array[index + 1] & 0xff) << 48 |
                ((long) array[index + 2] & 0xff) << 40 |
                ((long) array[index + 3] & 0xff) << 32 |
                ((long) array[index + 4] & 0xff) << 24 |
                ((long) array[index + 5] & 0xff) << 16 |
                ((long) array[index + 6] & 0xff) <<  8 |
                (long) array[index + 7] & 0xff;
    }
    
    public static long getLong6(byte[] array, int index) {
        return  ((long) array[index] & 0xff) << 40 |
                ((long) array[index + 1] & 0xff) << 32 |
                ((long) array[index + 2] & 0xff) << 24 |
                ((long) array[index + 3] & 0xff) << 16 |
                ((long) array[index + 4] & 0xff) <<  8 |
                (long) array[index + 5] & 0xff;
    }

    public static long getLong4(byte[] array, int index) {
        return  (array[index]     & 0xff) << 24 |
                (array[index + 1] & 0xff) << 16 |
                (array[index + 2] & 0xff) <<  8 |
                array[index + 3] & 0xff;
    }


    public static int getInt(byte[] array, int index) {
        return  (array[index]     & 0xff) << 24 |
                (array[index + 1] & 0xff) << 16 |
                (array[index + 2] & 0xff) <<  8 |
                array[index + 3] & 0xff;
    }

    public static int getInt2(byte[] array, int index) {
        return (int) (array[index] << 8 | array[index + 1] & 0xFF) & 0xffff;
    }

    public static short getShort(byte[] array, int index) {
        return (short) (array[index] << 8 | array[index + 1] & 0xFF);
    }

    public static String prefixString(String src, int needLen, char cPrefix) {
        StringBuilder sb = new StringBuilder();
        sb.append(src);
        while (sb.length() < needLen) {
            sb.insert(0, cPrefix);
        }
        
        return sb.toString();
    }
    

    /**
     * 把8421BCD码转成字符串
     * @param array
     * @param offset 偏移量
     * @param length bcd码长度
     * @return
     */
    public static String getBCD8421String(byte[] array, int offset, int length) {
        StringBuilder sb = new StringBuilder();
        int i = offset;

        // skip the 0
        while ( i < (length + offset) && array[i] == 0 ) {
            i++;
        }

        if (i < (length + offset)) {
            sb.append(Integer.toHexString(array[i++]&0xFF));
        }
        
        while (i < (length + offset)) {
            String temp = Integer.toHexString(array[i++]&0xFF);
            if(temp.length() == 1) {
                sb.append("0");
            }
            sb.append(temp);
        }
        if (sb.length() == 0) {
            return "0";
        } else {
            return sb.toString();
        }
    }
    
    /**
     * 把8421BCD码转成字符串, 
     * @param array
     * @param offset 偏移量
     * @param length bcd码长度
     * @param skipZero 对于前面是0的是否跳过, 比如0001, ture结果为'1'
     * @return
     */
    public static String getBCD8421String(byte[] array, int offset, int length, boolean skipZero) {
        StringBuilder sb = new StringBuilder();
        int i = offset;
        
        // skip the 0
        if (skipZero) {
            while (array[i] == 0 && i < (length + offset)) {
                i++;
            }
        }
        
        if (i < (length + offset)) {
            sb.append(Integer.toHexString(array[i++]&0xFF));
            if (!skipZero && sb.length() == 1) {
                sb.insert(0, "0");
            }
        }
        
        while (i < (length + offset)) {
            String temp = Integer.toHexString(array[i++]&0xFF);
            if(temp.length() == 1) {
                sb.append("0");
            }
            sb.append(temp);
        }
        if (sb.length() == 0) {
            return "0";
        } else {
            return sb.toString();
        }
    }
    
    /**
     * 把String转成BCD8421码, 不足length位，前面补0
     * @param array
     * @param offset
     * @param length bcd len 
     * @param str
     */
    public static void setBCD8421(byte[] array, int offset, int length, String str) {
        String prefixedStr = BigEndian.prefixString(str, length*2, '0');
        int index = offset;
        int i = 0;
        int strLen = prefixedStr.length();
        while (i < strLen) {
            int val0 = Integer.valueOf(prefixedStr.charAt(i++));
            int val1 = Integer.valueOf(prefixedStr.charAt(i++));
            array[index++] = (byte) (((val0 << 4) & 0xf0) | (val1 & 0x0f));
        }
    }
    
    /** 将一个BCD码转成数值, 比如0x12 成为12 */
    public static int getBCDValue(byte num){
        int bcdNum = 0;
            
        bcdNum = (num & 0x0F) + ((num & 0xf0)>>4) * 10;
        if (bcdNum > 99) {
            logger.warn("getBCDValue: wrong bcd:" + bcdNum);
        }

        return bcdNum;                                                                                                                                                     
    }
    
    /** 将一个数值转成BCD字节, 比如12 成为0x12 */
    public static byte toBCDCode(int value) {
        if (value > 99) {
            logger.warn("toBCDCode: wrong param:" + value);
        }
        return (byte)((value%10) | (value/10<<4) & 0xf0);
    }

	public static void main(String[] args) {
		
		byte[] buf = new byte[32];
		// setLong4(buf, 0, 0x1234);
		setString(buf, 0, "192.168.1.178", 32);
		setOctetString(buf, 16, "192.168.1.178", 16);
		for (int i = 0; i < 32; i++) {
			System.out.print(String.format(" 0x%02x", buf[i]));
		}
		System.out.println();
		
		byte[] bPlateArray = new byte[31];
		String plate = "苏AX6639";
		setOctetString(bPlateArray, 0, plate, 21);
		System.out.println(plate + ":"
				+ Utils.bytesToHexString(bPlateArray, 0, bPlateArray.length));
		System.out.println("The result bytes is:"
				+ getOctetString(bPlateArray, 0, 21));
		
		
		// prefixString
		String tel = "13054678";
		String preTel = prefixString(tel, 12, '0');
		byte[] bPreTel = new byte[12];
		setOctetString(bPreTel, 0, preTel, 12);
		System.out.println("src:" + tel + "\t" + " result:" + preTel);
		System.out.println("The result bytes is:"
		          + Utils.bytesToHexString(bPreTel, 0, bPreTel.length));
	}

}
